export function setItem(key, value) {
  return new Promise((resolve, reject) => {
    const data = {}
    data[key] = value
    chrome.storage.local.set(data, () => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError)
      } else {
        resolve()
      }
    })
  })
}

export function getItem(key) {
  return new Promise((resolve, reject) => {
    chrome.storage.local.get(key, (result) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError)
      } else {
        resolve(result[key] || null)
      }
    })
  })
}

export function simulateTyping(inputBox, text) {
  let i = 0

  function type() {
    if (i < text.length) {
      let typingSpeed = Math.floor(Math.random() * (500 - 50 + 1)) + 50

      // 强制设置焦点，确保输入框激活
      inputBox.focus()
      inputBox.value += text.charAt(i)
      // 模拟偶尔的删除和修正
      if (Math.random() < 0.1 && i > 0) {
        // 删除一个字符，稍作停顿，再重新输入正确字符
        inputBox.value = inputBox.value.slice(0, -1)
        const event = new Event('input', { bubbles: true })
        inputBox.dispatchEvent(event)
        setTimeout(type, typingSpeed)
        return
      }

      // 触发input事件
      const event = new Event('input', { bubbles: true })
      inputBox.dispatchEvent(event)
      i++
      setTimeout(type, typingSpeed)
    }
  }
  type()
}

export async function getTextFromClipboard() {
  try {
    const clipboardText = await navigator.clipboard.readText()
    return clipboardText
  } catch (error) {
    console.error('无法读取剪切板内容:', error)
    return ''
  }
}

export function startTyping(from = '', value = '') {
  const inputBox = document.activeElement
  if (inputBox && (inputBox.tagName === 'INPUT' || inputBox.tagName === 'TEXTAREA')) {
    inputBox.focus()
    if (from === 'silder') {
      if (value && value.length) {
        simulateTyping(inputBox, value)
      }
      return
    }
    getTextFromClipboard().then((text) => {
      if (text && text.length) {
        simulateTyping(inputBox, text)
      }
    })
  }
}

// 模拟鼠标移动的函数
function simulateMouseMove(startX, startY, endX, endY) {
  console.log('startX, startY, endX, endY: ', startX, startY, endX, endY)
  const moveSteps = 15
  let currentX = startX
  let currentY = startY

  // 使用 setTimeout 模拟平滑的鼠标移动
  for (let i = 0; i < moveSteps; i++) {
    setTimeout(
      () => {
        // 计算每步移动的偏移
        const stepX = (endX - currentX) / (moveSteps - i)
        const stepY = (endY - currentY) / (moveSteps - i)

        currentX += stepX
        currentY += stepY

        // 触发 mousemove 事件
        const mouseMoveEvent = new MouseEvent('mousemove', {
          bubbles: true,
          cancelable: true,
          clientX: currentX,
          clientY: currentY,
          view: window,
        })
        document.dispatchEvent(mouseMoveEvent)
      },
      i * Math.random() * 100,
    ) // 每次移动之间有随机延迟
  }
}

export function simulateClickElement(element) {
  // 获取元素的位置信息
  const rect = element.getBoundingClientRect()

  // 计算元素的中心点
  const centerX = rect.left + rect.width / 2;
  const centerY = rect.top + rect.height / 2;

  // 引入一定范围内的随机偏移，模拟不完美的点击
  const offsetX = (Math.random() - 0.5) * rect.width * 0.5;  // 偏移范围为元素宽度的50%
  const offsetY = (Math.random() - 0.5) * rect.height * 0.5; // 偏移范围为元素高度的50%

  // 计算目标点击位置
  const x = centerX + offsetX;
  const y = centerY + offsetY;

  // 随机化鼠标起始位置，以模拟更自然的点击行为
  const startX = Math.random() * (window.innerWidth - 100)
  const startY = Math.random() * (window.innerHeight - 100)

  // 鼠标事件的选项
  const eventOpts = {
    bubbles: true,
    cancelable: true,
    view: window,
    clientX: x,
    clientY: y,
  }

  // 1. 模拟鼠标从随机位置移动到目标位置（平滑移动）
  simulateMouseMove(startX, startY, x, y)

  // 2. 模拟 mouse down（鼠标按下）
  setTimeout(() => {
    element.dispatchEvent(new MouseEvent('mousedown', eventOpts))
  }, Math.random() * 50) // 模拟轻微延迟，避免过于机械

  // 3. 模拟 mouse up（鼠标松开）
  setTimeout(
    () => {
      element.dispatchEvent(new MouseEvent('mouseup', eventOpts))

      element.dispatchEvent(new MouseEvent('click', eventOpts))
    },
    Math.random() * 300 + 100,
  ) // 模拟延迟，增加自然感

  // 4. 触发点击事件
  setTimeout(() => {
    element.dispatchEvent(new MouseEvent('click', eventOpts));
    element.focus?.()
  }, Math.random() * 150 + 100); // 模拟更多延迟，确保行为自然



  // 4. 触发点击事件
  // setTimeout(
  //   () => {
  //     if (element.click) {
  //       console.log('element.click')
  //       // element.click() // 调用 click() 方法来执行浏览器默认行为
  //     } else {
  //       console.log('PointerEvent.click')
  //       element.dispatchEvent(new PointerEvent('click', { bubbles: true }))
  //     }

  //     // 5. 给元素添加焦点，模拟用户点击后可能对输入框等元素进行焦点操作
  //     element.focus?.()
  //   },
  //   Math.random() * 150 + 100,
  // )
}

export function generateLoopSelectors(
  elements,
  { max, attrId, frameSelector, reverseLoop, startIndex = 0 },
) {
  const selectors = []
  let elementsList = elements

  if (reverseLoop) {
    elementsList = Array.from(elements).reverse()
  }

  elementsList.forEach((el, index) => {
    if (max > 0 && selectors.length - 1 > max) return

    const attrName = 'automa-loop'
    const attrValue = `${attrId}--${(startIndex || 0) + index}`

    el.setAttribute(attrName, attrValue)
    selectors.push(`${frameSelector}[${attrName}="${attrValue}"]`)
  })

  return selectors
}

export function elementSelectorInstance() {
  const rootElementExist = document.querySelector('#app-container.automa-element-selector')

  if (rootElementExist) {
    rootElementExist.style.display = 'block'

    return true
  }

  return false
}

export function getElementRect(target, withAttributes) {
  if (!target) return {}

  const { x, y, height, width } = target.getBoundingClientRect()
  const result = {
    width: width + 4,
    height: height + 4,
    x: x - 2,
    y: y - 2,
  }

  if (withAttributes) {
    const attributes = {}

    Array.from(target.attributes).forEach(({ name, value }) => {
      if (name === 'automa-el-list') return

      attributes[name] = value
    })

    result.attributes = attributes
    result.tagName = target.tagName
  }

  return result
}

export function getElementPath(el, root = document.documentElement) {
  const path = [el]

  /* eslint-disable-next-line */
  while ((el = el.parentNode) && !el.isEqualNode(root)) {
    path.push(el)
  }

  return path
}

export function generateXPath(element, root = document.body) {
  if (!element) return null
  if (element.id !== '') return `id("${element.id}")`
  if (element === root) return `//${element.tagName}`

  let ix = 0
  const siblings = element.parentNode.childNodes

  for (let index = 0; index < siblings.length; index += 1) {
    const sibling = siblings[index]

    if (sibling === element) {
      return `${generateXPath(element.parentNode)}/${element.tagName}[${ix + 1}]`
    }

    if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
      ix += 1
    }
  }

  return null
}

export function automaRefDataStr(varName) {
  return `
function findData(obj, path) {
  const paths = path.split('.');
  const isWhitespace = paths.length === 1 && !/\\S/.test(paths[0]);

  if (path.startsWith('$last') && Array.isArray(obj)) {
    paths[0] = obj.length - 1;
  }

  if (paths.length === 0 || isWhitespace) return obj;
  else if (paths.length === 1) return obj[paths[0]];

  let result = obj;

  for (let i = 0; i < paths.length; i++) {
    if (result[paths[i]] == undefined) {
      return undefined;
    } else {
      result = result[paths[i]];
    }
  }

  return result;
}
function automaRefData(keyword, path = '') {
  const data = ${varName}[keyword];

  if (!data) return;

  return findData(data, path);
}
  `
}

function messageTopFrame(windowCtx) {
  return new Promise((resolve) => {
    let timeout = null

    const messageListener = ({ data }) => {
      if (data.type !== 'automa:the-frame-rect') return

      clearTimeout(timeout)
      windowCtx.removeEventListener('message', messageListener)
      resolve(data.frameRect)
    }

    timeout = setTimeout(() => {
      windowCtx.removeEventListener('message', messageListener)
      resolve(null)
    }, 5000)

    windowCtx.addEventListener('message', messageListener)
    windowCtx.top.postMessage({ type: 'automa:get-frame' }, '*')
  })
}
export async function getElementPosition(element) {
  const elWindow = element.ownerDocument.defaultView
  const isInFrame = elWindow !== window.top
  const { width, height, x, y } = element.getBoundingClientRect()

  const position = {
    x: x + width / 2,
    y: y + height / 2,
  }

  if (!isInFrame) return position

  try {
    const frameEl = elWindow.frameElement
    let frameRect = null

    if (frameEl) {
      frameRect = frameEl.getBoundingClientRect()
    } else {
      frameRect = await messageTopFrame(elWindow)

      if (!frameRect) throw new Error('Iframe not found')
    }

    position.x += frameRect.x
    position.y += frameRect.y

    return position
  } catch (error) {
    console.error(error)
    return position
  }
}
